﻿#pragma once

#include "MathCommon.h"
#include "Vec3.h"

#include "Containers/String.h"

#include "Quat.m.h"

struct SMatrix3x3;

//for normalized Quat
//w= cos(0.5*Angle)
//[x,y,z]= sin（0.5*Angle）*Axis
RSTRUCT()
struct WHENGINE_API SQuat
{
	ROBJECT

	RFIELD()
	Float X;
	RFIELD()
	Float Y;
	RFIELD()
	Float Z;
	RFIELD()
	Float W;

	SQuat()
		:X(0), Y(0), Z(0), W(1)
	{}

	SQuat(Float InX, Float InY, Float InZ, Float InW)
		:X(InX), Y(InY), Z(InZ), W(InW)
	{}

	static SQuat FromEuler(const SVec3& InRandian);

	SQuat(const SVec3& Axis, Float InRandian);

	SQuat(const SMatrix3x3& Matrix);

	SVec3 ToEuler() const;

	SQuat operator*(const SQuat& Q) const;

	//Rotate vector
	SVec3 operator*(const SVec3& InVector) const;

	//scale vector
	SQuat operator*(const Float& InScale) const;

	SQuat operator/(const Float& InScale) const;

	Float DotProduct(const SQuat& Other) const;
	
	// add like vector
	SQuat operator+(const SQuat& Other) const;

	//get rotate axis 
	SVec3 GetRotationAxis() const;

	//get rotate Angle 
	Float GetRotationAngle() const;

	SQuat Inverse() const;


	bool IsNormalized() const;

	void Normalize();

	Float GetLength() const;


	SVec3 GetForwardDirection() const;
	SVec3 GetRightDirection() const;
	SVec3 GetUpDirection() const;

	CString ToString() const;

	//glm::quat ToGlm() const ;
	
	void ToFloatArray(float OutArray[4]) const;
};

//Spherical Linear Interpolation
//slower than Nlerp, but have a uniform rotate speed
WHENGINE_API SQuat Slerp(const SQuat& A, const SQuat& B, Float Alpha);

//return a normalized quat
//this interpolation do not have a uniform rotate speed, rotate fast at begin and end
WHENGINE_API SQuat Nlerp(const SQuat& A, const SQuat& B, Float Alpha);

//lerp like vector, result is not unit vector / pure quat
WHENGINE_API SQuat Lerp(const SQuat& A, const SQuat& B, Float Alpha);

